!> 蛙跳法测试
module test_seakeeping_leapfrog

    use testdrive, only: new_unittest, unittest_type, error_type, check
    use seakeeping_module, only: wp => sk_real_kind, leapfrog_type
    implicit none

    private
    public :: collect_leapfrog

contains

    subroutine collect_leapfrog(testsuite)
        type(unittest_type), intent(out), allocatable :: testsuite(:)

        allocate (testsuite, source=[ &
                  new_unittest('leapfrog', test_leapfrog) &
                  ])

    end subroutine collect_leapfrog

    subroutine test_leapfrog(error)
        type(error_type), allocatable, intent(out) :: error
        real(wp) :: x(3), v(3), a(3), dt, t
        integer :: i
        type(leapfrog_type) :: leapfrog
        real(wp), parameter :: x0(*) = [0.0_wp, 0.0_wp, -4.9_wp], &
                               v0(*) = [0.0_wp, 0.0_wp, -9.79999924_wp], &
                               a0(*) = [0.0_wp, 0.0_wp, -9.8_wp]

        dt = 0.1_wp
        t = 0
        x = 0
        v = 0

        call leapfrog%integrate(func, t, x, v, a, dt, 3)

        call leapfrog%step(t, x, v, a, dt, 10, 3)

        call check(error, t, 1.00_wp, more='leapfrog: t')
        if (allocated(error)) return

        do i = 1, 3
            call check(error, x(i), x0(i), more='leapfrog: x')
            if (allocated(error)) return
            call check(error, leapfrog%v(i), v0(i), more='leapfrog: v')
            if (allocated(error)) return
            call check(error, a(i), a0(i), more='leapfrog: a')
            if (allocated(error)) return
        end do

    contains

        !> 三维自由落体运动
        subroutine func(t, x, v, a)
            real(wp), intent(in) :: x(:), v(:), t
            real(wp), intent(out) :: a(:)

            a = [0.0_wp, 0.0_wp, -9.8_wp]

        end subroutine func

    end subroutine test_leapfrog

end module test_seakeeping_leapfrog
